package edu.sjtu.grid.workflow.facts;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.dom4j.Element;

import edu.sjtu.grid.workflow.Util;

public class PCS {
	//private Facts facts = null;
	
	private double dataTransCost = 0;
	
	private int size = 0;
	private PC pcList[] = null;
	private double bandwidth[][] = null;
	
	private Map<String, PC> idToPC = null;
	
	public Map<String, PC> getIdToPC()
	{
		return this.idToPC;
	}
	
	@SuppressWarnings("unchecked")
	public PCS(Facts facts, Element ePCGraph)
	{
		//this.facts = facts;
		
		this.dataTransCost = Double.parseDouble(ePCGraph.attributeValue("data-trans-cost"));
		
		//size
		this.size = 0;
        for (Iterator<Element> i = ePCGraph.elementIterator("pc"); i.hasNext(); ) {
            i.next();
            this.size++;
        }
        
        //init
        this.pcList = new PC[size];
        this.bandwidth = new double[size][];
        for(int i=0; i<size; i++)
        {
        	this.bandwidth[i] = new double[size];
        	for(int j=0; j<size; j++)
        		this.bandwidth[i][j] = 0;
        }
        this.idToPC = new HashMap<String, PC>();
        	
        
		//id speed pay [cost | cycle cost1 time1 cost2 time2]
        int index = 0;
        for (Iterator<Element> i = ePCGraph.elementIterator("pc"); i.hasNext(); ) {
            Element ePC= (Element)i.next();
            this.pcList[index] = new PC(ePC, index);
            idToPC.put(this.pcList[index].getId(), this.pcList[index]);
            index++;
        }
        
        //bandwidth matrix
        for (Iterator<Element> i = ePCGraph.elementIterator("bandwidth"); i.hasNext(); ) {
        	Element eBandwidth= (Element)i.next();
        	String sRef1 = eBandwidth.attributeValue("ref1");
        	String sRef2 = eBandwidth.attributeValue("ref2");
        	String sSpeed = eBandwidth.attributeValue("speed");
        	PC pc1 = idToPC.get(sRef1);
        	PC pc2 = idToPC.get(sRef2);
        	double speed = Double.parseDouble(sSpeed);
        	this.bandwidth[pc1.getIndex()][pc2.getIndex()] = speed;
        	this.bandwidth[pc2.getIndex()][pc1.getIndex()] = speed;
        }
	}
	
	public int getSize() {
		return size;
	}

	public PC[] getPcList() {
		return pcList;
	}

	public double[][] getBandwidth() {
		return bandwidth;
	}
	
	public double getBandwidth(PC pc1, PC pc2)
	{
		return bandwidth[pc1.getIndex()][pc2.getIndex()];
	}
	
	public double getDataTransCost()
	{
		return this.dataTransCost;
	}

	public PC getCheepestPC()
	{
		PC r = null;
		double cheapest = Double.MAX_VALUE;
		for(PC pc : pcList)
		{
			if(Util.isSmall(pc.getCost().getCheapestCost() , cheapest))
			{
				r = pc;
				cheapest = pc.getCost().getAvgCost();
			}
		}
		return r;
	}
	
	public PC getAvgCheepestPC()
	{
		PC r = null;
		double cheapest = Double.MAX_VALUE;
		for(PC pc : pcList)
		{
			if(Util.isSmall(pc.getCost().getAvgCost() , cheapest))
			{
				r = pc;
				cheapest = pc.getCost().getAvgCost();
			}
		}
		return r;
	}
	
	public double getAvgSpeed()
	{
		if(this.pcList == null || this.pcList.length <= 0)
			return Double.MAX_VALUE;
			
		double sumSpeed = 0;
		for(PC pc : this.pcList)
			sumSpeed += pc.getSpeed();
		return sumSpeed / pcList.length;
	}
	
	public double getFastestSpeed()
	{
		if(this.pcList == null || this.pcList.length <= 0)
			return Double.MIN_VALUE;
			
		double fastest = Double.MIN_VALUE;
		for(PC pc : this.pcList)
			fastest = Math.max(fastest, pc.getSpeed());
		return fastest;
	}
	
	public double getAvgBandwidth()
	{
		double sum = 0;
		for(int i=0; i<size; i++)
			for(int j=0; j<size; j++)
				sum += bandwidth[i][j];
		return sum/(size*size);
	}
	
	public String toString()
	{
		StringBuilder s = new StringBuilder();
		s.append("----------pcs----------\n");
		s.append("data-trans-cost:\t" + this.dataTransCost + "\n\n");
		s.append("index\tid\tspeed\tpay\t\tavgcost\tcost\n");
		for(int i=0; i<this.size; i++)
		{
			PC pc = this.pcList[i];
			s.append(pc.getIndex() + "\t");
			s.append(pc.getId() + "\t");
			s.append(pc.getSpeed() + "\t");
			s.append(pc.getCost().getPayString() + "\t");
			s.append(Util.formatOutputDouble(pc.getCost().getAvgCost()) + "\t");
			s.append(pc.getCost().getCostString());
			s.append("\n");
		}
		
		s.append("\nbandwidth matrix\n");
		for(int i=0; i<this.size; i++)
		{
			for(int j=0; j<this.size; j++)
				s.append(this.bandwidth[i][j] + "   ");
			s.append("\n");
		}
		return s.toString();
	}
	
	

}
